home *** CD-ROM | disk | FTP | other *** search
/ PC World 2006 October / PCWorld_2006-10_cd.bin / v cisle / pdffc / ps2pdf995.exe / pdf995 / res / convert / ps2ascii.ps < prev    next >
Text File  |  2002-12-27  |  46KB  |  1,523 lines

  1. % This file has been modified by pdf995 on Dec 27, 2002
  2. %    Copyright (C) 1991, 1995, 1996, 1998, 1999 Aladdin Enterprises.  All rights reserved.
  3. % This software is provided AS-IS with no warranty, either express or
  4. % implied.
  5. % This software is distributed under license and may not be copied,
  6. % modified or distributed except as expressly authorized under the terms
  7. % of the license contained in the file LICENSE in this distribution.
  8. % For more information about licensing, please refer to
  9. % http://www.ghostscript.com/licensing/. For information on
  10. % commercial licensing, go to http://www.artifex.com/licensing/ or
  11. % contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  12. % San Rafael, CA  94903, U.S.A., +1(415)492-9861.
  13.  
  14. % $Id: ps2ascii.ps,v 1.3.2.2 2002/04/02 13:57:27 mpsuzuki Exp $
  15. % Extract the ASCII text from a PostScript file.  Nothing is displayed.
  16. % Instead, ASCII information is written to stdout.  The idea is similar to
  17. % Glenn Reid's `distillery', only a lot more simple-minded, and less robust.
  18.  
  19. % If SIMPLE is defined, just the text is written, with a guess at line
  20. % breaks and word spacing.  If SIMPLE is not defined, lines are written
  21. % to stdout as follows:
  22. %
  23. %    F <height> <width> (<fontname>)
  24. %        Indicate the font height and the width of a space.
  25. %
  26. %    P
  27. %        Indicate the end of the page.
  28. %    S <x> <y> (<string>) <width>
  29. %        Display a string.
  30. %
  31. % <width> and <height> are integer dimensions in units of 1/720".
  32. % <x> and <y> are integer coordinates, in units of 1/720", with the origin
  33. %   at the lower left.
  34. % <string> and <fontname> are strings represented with the standard
  35. %   PostScript escape conventions.
  36.  
  37. % If COMPLEX is defined, the following additional types of lines are
  38. % written to stdout.
  39. %
  40. %    C <r> <g> <b>
  41. %        Indicate the current color.
  42. %
  43. %    I <x> <y> <width> <height>
  44. %        Note the presence of an image.
  45. %
  46. %    R <x> <y> <width> <height>
  47. %        Fill a rectangle.
  48. %
  49. % <r>, <g>, and <b> are RGB values expressed as integers between 0 and 1000.
  50. %
  51. % Note that future versions of this program (in COMPLEX mode) may add
  52. %   other output elements, so programs parsing the output should be
  53. %   prepared to ignore elements that they do not recognize.
  54.  
  55. % Note that this code will only work in all cases if systemdict is writable
  56. % and if `binding' the definitions of operators defined as procedures
  57. % is deferred.  For this reason, it is normally invoked with
  58. %    gs -q -dNODISPLAY -dNOBIND -dWRITESYSTEMDICT ps2ascii.ps
  59.  
  60. % Thanks to:
  61. %    J Greely <jgreely@cis.ohio-state.edu> for improvements to this code;
  62. %    Jerry Whelan <jerryw@abode.ccd.bnl.gov> for motivating other improvements;
  63. %    David M. Jones <dmjones@theory.lcs.mit.edu> for improvements noted below.
  64.  
  65. %%  Additional modifications by David M. Jones
  66. %%  (dmjones@theory.lcs.mit.edu), December 23, 1997
  67. %%  
  68. %%  (a) Rewrote forall loop at the end of .show.write.  This fixes a
  69. %%      stack leakage problem, but the changes are more significant
  70. %%      than that.  
  71. %% 
  72. %%      .char.map includes the names of all characters in the
  73. %%      StandardEncoding, ISOLatin1Encoding, OT1Encoding and
  74. %%      T1Encoding vectors.  Thus, if the Encoding vector for the
  75. %%      current font contains a name that is not in .char.map, it's
  76. %%      redundant to check if the Encoding vector is equal to one of
  77. %%      the known vectors.  Previous versions of ps2ascii would give
  78. %%      up at this point, and substitute an asterisk (*) for the
  79. %%      character.  I've taken the liberty of instead using the
  80. %%      OT1Encoding vector to translate the character, on the grounds
  81. %%      that in the cases I'm most interested in, a font without a
  82. %%      useful Encoding vector was most likely created by a DVI to PS
  83. %%      converter such as dvips or DVILASER (and OT1Encoding is
  84. %%      largely compatible with StandardEncoding anyway).  [Note that
  85. %%      this does not make my earlier changes to support dvips (see
  86. %%      fix (a) under my 1996 changes) completely obsolete, since
  87. %%      there's additional useful information I can extract in that
  88. %%      case.]
  89. %%      
  90. %%      Overall, this should provide better support for some documents
  91. %%      (e.g, DVILASER documents will no longer be translated into a
  92. %%      series of *'s) without breaking any other documents any worse
  93. %%      than they already were broken.
  94. %% 
  95. %%  (b) Fixed two bugs in dvips.df-tail: (1) changed "dup 127" to "dup
  96. %%      128" to fix fencepost error, and (2) gave each font it's own
  97. %%      FontName rather than having all fonts share the same name.
  98. %%  
  99. %%  (c) Added one further refinement to the heuristic for detecting
  100. %%      paragraph breaks: do not ever start a new paragraph after a
  101. %%      line ending in a hyphen.
  102. %% 
  103. %%  (d) Added a bunch of missing letters from the T1Encoding,
  104. %%      OT1Encoding and ISOLatin1Encoding vectors to .letter.chars to
  105. %%      improve hyphen-elimination algorithm.  This still won't help
  106. %%      if there's no useful Encoding vector.
  107. %% 
  108. %%  NOTE: A better solution to the problem of missing Encoding vectors
  109. %%  might be to redefine definefont to check whether the Encoding
  110. %%  vector is sensible and, if not, replace it by a default.  This
  111. %%  would alleviate the need for constant tests in the .show.write
  112. %%  loop, as well as automatically solving the problem noted in fix
  113. %%  (d) above, and the similar problem with .break.chars.  This should
  114. %%  be investigated.  Also, the hyphen-elimination algorithm really
  115. %%  needs to be looked at carefully and rethought.
  116.  
  117. %%* Modifications to ps2ascii.ps by David M. Jones
  118. %%* (dmjones@theory.lcs.mit.edu), June 25-July 8, 1996
  119.  
  120. %%* Modifications:
  121. %%* 
  122. %%* (a) added code to give better support for dvips files by providing
  123. %%*     FontBBox's, FontName's and Encoding vectors for downloaded
  124. %%*     bitmap fonts.  This is done by using dvips's start-hook to
  125. %%*     overwrite the df-tail and D procedures that dvips uses to
  126. %%*     define its Type 3 bitmap fonts.  Thus, this change should
  127. %%*     provide better support for dvips-generated PS files without
  128. %%*     affecting the handling of other documents.
  129. %%* 
  130. %%* (b) Fixed two bugs that could potentially affect any PS file, not
  131. %%*     just those created by dvips: (1) added missing "get" operator
  132. %%*     in .show.write and (2) fixed bug that caused a hyphen at the
  133. %%*     end of a line to be replaced by a space rather than begin
  134. %%*     deleted.  Note that the first bug was a source of stack
  135. %%*     leakage, causing ps2ascii to run out of operand stack space
  136. %%*     occasionally.
  137. %%* 
  138. %%*     Search for "%%* BF" to find these modifications.
  139. %%*     
  140. %%* (c) Improved the heuristic for determining whether a line break
  141. %%*     has occurred and whether a line break represents a paragraph
  142. %%*     break.  Previously, any change in the vertical position caused
  143. %%*     a line break; now a line break is only registered if the
  144. %%*     change is larger than the height of the current font.  This
  145. %%*     means that superscripts, subscripts, and such things as
  146. %%*     shifted accents generated by TeX won't cause line breaks.
  147. %%*     Paragraph-recognition is now done by comparing the indentation
  148. %%*     of the new line to the indentation of the previous line and by
  149. %%*     comparing the vertical distance between the new line and the
  150. %%*     previous line to the vertical distance between the previous
  151. %%*     line and its predecessor.
  152. %%*     
  153. %%* (d) Added a hook for renaming the files where stdout and stderr
  154. %%*     go.
  155. %%* 
  156. %%* In general, my additions or changes to the code are described in
  157. %%* comments beginning with "%%*".  However, there are numerous other
  158. %%* places where I have either re-formatted code or added comments to
  159. %%* the code while I was trying to understand it.  These are usually
  160. %%* not specially marked.
  161. %%* 
  162.  
  163. /QUIET true def
  164. systemdict wcheck { systemdict } { userdict } ifelse begin
  165. /.max where { pop } { /.max { 2 copy lt { exch } if pop } bind def } ifelse
  166. /COMPLEX dup where { pop true } { false } ifelse def
  167. /SIMPLE dup where { pop true } { false } ifelse def
  168. /setglobal where
  169.  { pop currentglobal /setglobal load true setglobal }
  170.  { { } }
  171. ifelse
  172.  
  173. % Define a way to store and retrieve integers that survives save/restore.
  174. /.i.string0 (0               ) def
  175. /.i.string .i.string0 length string def
  176. /.iget { cvi } bind def
  177. /.iput { exch //.i.string exch copy cvs pop } bind def
  178. /.inew { //.i.string0 dup length string copy } bind def
  179.  
  180. % We only want to redefine operators if they are defined already.
  181.  
  182. /codef { 1 index where { pop def } { pop pop } ifelse } def
  183.  
  184. % Redefine the end-of-page operators.
  185.  
  186. /erasepage { } codef
  187. /copypage { SIMPLE { (\014) } { (P\n) } ifelse //print } codef
  188. /showpage { copypage erasepage initgraphics } codef
  189.  
  190. % Redefine the fill operators to detect rectangles.
  191.  
  192. /.orderrect    % <llx> <lly> <urx> <ury> .orderrect <llx> <lly> <w> <h>
  193.  {    % Ensure llx <= urx, lly <= ury.
  194.    1 index 4 index lt { 4 2 roll } if
  195.    dup 3 index lt { 3 1 roll exch } if
  196.    exch 3 index sub exch 2 index sub
  197.  } odef
  198. /.fillcomplex
  199.  {    % Do a first pass to see if the path is all rectangles in
  200.     % the output coordinate system.  We don't worry about overlapping
  201.     % rectangles that might be partially not filled.
  202.     % Stack: mark llx0 lly0 urx0 ury0 ... true mark x0 y0 ...
  203.    mark true mark
  204.     % Add a final moveto so we pick up any trailing unclosed subpath.
  205.    0 0 itransform moveto
  206.     { .coord counttomark 2 gt
  207.        { counttomark 4 gt { .fillcheckrect } { 4 2 roll pop pop }  ifelse }
  208.       if
  209.     }
  210.     { .coord }
  211.     { cleartomark not mark exit }
  212.     { counttomark -2 roll 2 copy counttomark 2 roll .fillcheckrect }
  213.    pathforall cleartomark
  214.     { .showcolor counttomark 4 idiv
  215.        { counttomark -4 roll .orderrect
  216.      (R ) //print .show==4
  217.        }
  218.       repeat pop
  219.     }
  220.     { cleartomark
  221.     }
  222.    ifelse
  223.  } odef
  224. /.fillcheckrect
  225.  {    % Check whether the current subpath is a rectangle.
  226.     % If it is, add it to the list of rectangles being accumulated;
  227.     % if not exit the .fillcomplex loop.
  228.     % The subpath has not been closed.
  229.     % Stack: as in .fillcomplex, + newx newy
  230.    counttomark 10 eq { 9 index 9 index 4 2 roll } if
  231.    counttomark 12 ne { cleartomark not mark exit } if
  232.    12 2 roll
  233.     % Check for the two possible forms of rectangles:
  234.     %    x0 y0  x0 y1  x1 y1  x1 y0  x0 y0
  235.     %    x0 y0  x1 y0  x1 y1  x0 y1  x0 y0
  236.    9 index 2 index eq 9 index 2 index eq and
  237.    10 index 9 index eq
  238.     {    % Check for first form.
  239.       7 index 6 index eq and 6 index 5 index eq and 3 index 2 index eq and
  240.     }
  241.     {    % Check for second form.
  242.       9 index 8 index eq and
  243.       8 index 7 index eq and 5 index 4 index eq and 4 index 3 index eq and
  244.     }
  245.    ifelse not { cleartomark not mark exit } if
  246.     % We have a rectangle.
  247.    pop pop pop pop 4 2 roll pop pop 8 4 roll
  248.  } odef
  249. /eofill { COMPLEX { .fillcomplex } if newpath } codef
  250. /fill { COMPLEX { .fillcomplex } if newpath } codef
  251. /rectfill { gsave newpath .rectappend fill grestore } codef
  252. /ueofill { gsave newpath uappend eofill grestore } codef
  253. /ufill { gsave newpath uappend fill grestore } codef
  254.  
  255. % Redefine the stroke operators to detect rectangles.
  256.  
  257. /rectstroke
  258.  { gsave newpath
  259.    dup type dup /arraytype eq exch /packedarraytype eq or
  260.     { dup length 6 eq { exch .rectappend concat } { .rectappend } ifelse }
  261.     { .rectappend }
  262.    ifelse stroke grestore
  263.  } codef
  264. /.strokeline    % <fromx> <fromy> <tox> <toy> .strokeline <tox> <toy>
  265.         % Note: fromx and fromy are in output coordinates;
  266.         % tox and toy are in user coordinates.
  267.  { .coord 2 copy 6 2 roll .orderrect
  268.     % Add in the line width.  Assume square or round caps.
  269.    currentlinewidth 2 div dup .dcoord add abs 1 .max 5 1 roll
  270.    4 index add 4 1 roll 4 index add 4 1 roll
  271.    4 index sub 4 1 roll 5 -1 roll sub 4 1 roll
  272.    (R ) //print .show==4
  273.  } odef
  274. /.strokecomplex
  275.  {    % Do a first pass to see if the path is all horizontal and vertical
  276.     % lines in the output coordinate system.
  277.     % Stack: true mark origx origy curx cury
  278.    true mark null null null null
  279.     { .coord 6 2 roll pop pop pop pop 2 copy }
  280.     { .coord 1 index 4 index eq 1 index 4 index eq or
  281.        { 4 2 roll pop pop }
  282.        { cleartomark not mark exit }
  283.       ifelse
  284.     }
  285.     { cleartomark not mark exit }
  286.     { counttomark -2 roll 2 copy counttomark 2 roll
  287.       1 index 4 index eq 1 index 4 index eq or
  288.        { pop pop 2 copy }
  289.        { cleartomark not mark exit }
  290.       ifelse
  291.     }
  292.    pathforall cleartomark
  293.    0 currentlinewidth .dcoord 0 eq exch 0 eq or and
  294.     % Do the second pass to write out the rectangles.
  295.     % Stack: origx origy curx cury
  296.     { .showcolor null null null null
  297.        { 6 2 roll pop pop pop pop 2 copy .coord }
  298.        { .strokeline }
  299.        { }
  300.        { 3 index 3 index .strokeline }
  301.       pathforall pop pop pop pop
  302.     }
  303.    if
  304.  } odef
  305. /stroke { COMPLEX { .strokecomplex } if newpath } codef
  306. /ustroke
  307.  { gsave newpath
  308.    dup length 6 eq { exch uappend concat } { uappend } ifelse
  309.    stroke grestore
  310.  } codef
  311.  
  312. % The image operators must read the input and note the dimensions.
  313. % Eventually we should redefine these to detect 1-bit-high all-black images,
  314. % since this is how dvips does underlining (!).
  315.  
  316. /.noteimagerect        % <width> <height> <matrix> .noteimagerect -
  317.  { COMPLEX
  318.     { gsave setmatrix itransform 0 0 itransform
  319.       grestore .coord 4 2 roll .coord .orderrect
  320.       (I ) //print .show==4
  321.     }
  322.     { pop pop pop
  323.     }
  324.    ifelse
  325.  } odef
  326. /colorimage where
  327.  { pop /colorimage
  328.     { 1 index
  329.        { dup 6 add index 1 index 6 add index 2 index 5 add index }
  330.        { 6 index 6 index 5 index }
  331.       ifelse .noteimagerect gsave nulldevice //colorimage grestore
  332.     } codef
  333.  } if
  334. /.noteimage        % Arguments as for image[mask]
  335.  { dup type /dicttype eq
  336.     { dup /Width get 1 index /Height get 2 index /ImageMatrix get }
  337.     { 4 index 4 index 3 index }
  338.    ifelse .noteimagerect
  339.  } odef
  340. /image { .noteimage gsave nulldevice //image grestore } codef
  341. /imagemask { .noteimage gsave nulldevice //imagemask grestore } codef
  342.  
  343. % Output the current color if necessary.
  344. /.color.r .inew def
  345.   .color.r -1 .iput        % make sure we write the color at the beginning
  346. /.color.g .inew def
  347. /.color.b .inew def
  348. /.showcolor
  349.  { COMPLEX
  350.     { currentrgbcolor
  351.       1000 mul round cvi
  352.       3 1 roll 1000 mul round cvi
  353.       exch 1000 mul round cvi
  354.         % Stack: b g r
  355.       dup //.color.r .iget eq
  356.       2 index //.color.g .iget eq and
  357.       3 index //.color.b .iget eq and
  358.        { pop pop pop
  359.        }
  360.        { (C ) //print
  361.      dup //.color.r exch .iput .show==only
  362.          ( ) //print dup //.color.g exch .iput .show==only
  363.          ( ) //print dup //.color.b exch .iput .show==only
  364.      (\n) //print
  365.        }
  366.       ifelse
  367.     }
  368.    if
  369.  } bind def
  370.  
  371. % Redefine `show'.
  372.  
  373. % Set things up so our output will be in tenths of a point, with origin at
  374. % lower left.  This isolates us from the peculiarities of individual devices.
  375.  
  376. /.show.ident.matrix matrix def
  377. /.show.ident {        % - .show.ident <scale> <matrix>
  378. %   //.show.ident.matrix defaultmatrix
  379. %               % Assume the original transformation is well-behaved.
  380. %   0.1 0 2 index dtransform abs exch abs .max /.show.scale exch def
  381. %   0.1 dup 3 -1 roll scale
  382.   gsave initmatrix
  383.         % Assume the original transformation is well-behaved...
  384.   0.1 0 dtransform abs exch abs .max
  385.   0.1 dup scale .show.ident.matrix currentmatrix
  386.         % ... but undo any rotation into landscape orientation.
  387.   dup 0 get 0 eq {
  388.     1 get dup abs div 90 mul rotate
  389.     .show.ident.matrix currentmatrix
  390.   } if
  391.   grestore
  392. } bind def
  393.  
  394. /.coord {        % <x> <y> .coord <x'> <y'>
  395.   transform .show.ident exch pop itransform
  396.   exch round cvi exch round cvi
  397. } odef
  398.  
  399. /.dcoord {        % <dx> <dy> .coord <dx'> <dy'>
  400.         % Transforming distances is trickier, because
  401.         % the coordinate system might be rotated.
  402.    .show.ident pop 3 1 roll
  403.    exch 0 dtransform
  404.     dup mul exch dup mul add sqrt
  405.      2 index div round cvi
  406.    exch 0 exch dtransform
  407.     dup mul exch dup mul add sqrt
  408.      3 -1 roll div round cvi
  409. } odef
  410.  
  411. % Remember the current X, Y, and height.
  412. /.show.x .inew def
  413. /.show.y .inew def
  414. /.show.height .inew def
  415.  
  416. % Remember the last character of the previous string; if it was a
  417. % hyphen preceded by a letter, we didn't output the hyphen.
  418.  
  419. /.show.last (\000) def
  420.  
  421. % Remember the current font.
  422. /.font.name 130 string def
  423. /.font.name.length .inew def
  424. /.font.height .inew def
  425. /.font.width .inew def
  426.  
  427. %%* Also remember indentation of current line and previous vertical
  428. %%* skip
  429.  
  430. /.show.indent .inew def
  431. /.show.dy     .inew def
  432.  
  433. % We have to redirect stdout somehow....
  434.  
  435. /.show.stdout { (%stdout) (w) file } bind def
  436.  
  437. % Make sure writing will work even if a program uses =string.
  438. /.show.string =string length string def
  439. /.show.=string =string length string def
  440. /.show==only
  441.  { //=string //.show.=string copy pop
  442.    dup type /stringtype eq
  443.     { dup length //.show.string length le
  444.        { dup rcheck { //.show.string copy } if
  445.        } if
  446.     } if
  447.    .show.stdout exch write==only
  448.    //.show.=string //=string copy pop
  449.  } odef
  450. /.show==4
  451.  { %4 -1 roll .show==only ( ) //print
  452.    %3 -1 roll .show==only ( ) //print
  453.    %exch .show==only ( ) //print
  454.    %.show==only (\n) //print
  455.  
  456.  
  457. 4 -1 roll .show==only ( ) //print
  458. 3 -1 roll .show==only ( ) //print
  459. 2 -1 roll
  460. (\() //print
  461. .show.write
  462. (\) ) //print
  463. .show==only ( ) //print
  464. (\n) //print
  465.  
  466.  
  467.  } odef
  468.  
  469. /.showwidth    % Same as stringwidth, but disable COMPLEX so that
  470.         % we don't try to detect rectangles during BuildChar.
  471.  { COMPLEX
  472.     { /COMPLEX false def stringwidth /COMPLEX true def }
  473.     { stringwidth }
  474.    ifelse
  475.  } odef
  476.  
  477. /.showfont    % <string> .showfont <string>
  478.  { gsave
  479.     % Try getting the height and width of the font from the FontBBox.
  480.      currentfont /FontBBox .knownget not { {0 0 0 0} } if
  481.      aload pop      % llx lly urx ury
  482.      exch 4 -1 roll % lly ury urx llx
  483.      sub            % lly ury dx
  484.      3 1 roll exch  % dx ury lly
  485.      sub            % dx dy
  486.      2 copy .max 0 ne
  487.       { currentfont /FontMatrix get dtransform
  488.       }
  489.       {    pop pop
  490.     % Fonts produced by dvips, among other applications, have
  491.     % BuildChar procedures that bomb out when given unexpected
  492.     % characters, and there is no way to determine whether a given
  493.     % character will do this.  So for Type 1 fonts, we measure a
  494.     % typical character ('X'); for others, we punt.
  495.     currentfont /FontType get 1 eq
  496.      { (X) .showwidth pop dup 1.3 mul
  497.      }
  498.      {    % No safe way to get the character size.  Punt.
  499.        0 0
  500.      }
  501.     ifelse
  502.       }
  503.      ifelse .dcoord exch
  504.      currentfont /FontName .knownget not { () } if
  505.      dup type /stringtype ne { //.show.string cvs } if
  506.    grestore
  507.     % Stack: height width fontname
  508.    SIMPLE
  509.     { pop pop //.show.height exch .iput }
  510.     { 2 index //.font.height .iget eq
  511.       2 index //.font.width .iget eq and
  512.       1 index //.font.name 0 //.font.name.length .iget getinterval eq and
  513.        { pop pop pop
  514.        }
  515.        { (F ) //print
  516.      3 -1 roll dup //.font.height exch .iput .show==only ( ) //print
  517.          exch dup //.font.width exch .iput .show==only ( ) //print
  518.      dup length //.font.name.length exch .iput
  519.          //.font.name cvs .show==only (\n) //print
  520.        }
  521.       ifelse
  522.     }
  523.    ifelse
  524.  } odef
  525.  
  526. % Define the letters -- characters which, if they occur followed by a hyphen
  527. % at the end of a line, cause the hyphen and line break to be ignored.
  528. /.letter.chars 100 dict def
  529. mark
  530.   65 1 90 { dup 32 add } for
  531.     counttomark
  532.         { StandardEncoding exch get .letter.chars exch dup put }
  533.     repeat
  534. pop
  535.  
  536. %%* Add the rest of the letters from the [O]T1Encoding and
  537. %%* ISOLatin1Encoding vectors
  538.  
  539. mark
  540.     /AE
  541.     /Aacute
  542.     /Abreve
  543.     /Acircumflex
  544.     /Adieresis
  545.     /Agrave
  546.     /Aogonek
  547.     /Aring
  548.     /Atilde
  549.     /Cacute
  550.     /Ccaron
  551.     /Ccedilla
  552.     /Dcaron
  553.     /Eacute
  554.     /Ecaron
  555.     /Ecircumflex
  556.     /Edieresis
  557.     /Egrave
  558.     /Eng
  559.     /Eogonek
  560.     /Eth
  561.     /Gbreve
  562.     /Germandbls 
  563.     /IJ
  564.     /Iacute
  565.     /Icircumflex
  566.     /Idieresis
  567.     /Idot
  568.     /Igrave
  569.     /Lacute
  570.     /Lcaron
  571.     /Lslash
  572.     /Nacute
  573.     /Ncaron
  574.     /Ntilde
  575.     /OE
  576.     /Oacute
  577.     /Ocircumflex
  578.     /Odieresis
  579.     /Ograve
  580.     /Ohungarumlaut
  581.     /Oslash
  582.     /Otilde
  583.     /Racute
  584.     /Rcaron
  585.     /Sacute
  586.     /Scaron
  587.     /Scedilla
  588.     /Tcaron
  589.     /Tcedilla
  590.     /Thorn
  591.     /Uacute
  592.     /Ucircumflex
  593.     /Udieresis
  594.     /Ugrave
  595.     /Uhungarumlaut
  596.     /Uring
  597.     /Yacute
  598.     /Ydieresis
  599.     /Zacute
  600.     /Zcaron
  601.     /Zdot
  602.     /aacute
  603.     /abreve
  604.     /acircumflex
  605.     /adieresis
  606.     /ae
  607.     /agrave
  608.     /aogonek
  609.     /aring
  610.     /atilde
  611.     /cacute
  612.     /ccaron
  613.     /ccedilla
  614.     /dbar
  615.     /dcaron
  616.     /dotlessi
  617.     /dotlessj
  618.     /eacute
  619.     /ecaron
  620.     /ecircumflex
  621.     /edieresis
  622.     /egrave
  623.     /eng
  624.     /eogonek
  625.     /eth
  626.     /exclamdown
  627.     /ff
  628.     /ffi
  629.     /ffl
  630.     /fi
  631.     /fl
  632.     /gbreve
  633.     /germandbls
  634.     /iacute
  635.     /icircumflex
  636.     /idieresis
  637.     /igrave
  638.     /ij
  639.     /lacute
  640.     /lcaron
  641.     /lslash
  642.     /nacute
  643.     /ncaron
  644.     /ntilde
  645.     /oacute
  646.     /ocircumflex
  647.     /odieresis
  648.     /oe
  649.     /ograve
  650.     /ohungarumlaut
  651.     /oslash
  652.     /otilde
  653.     /questiondown
  654.     /racute
  655.     /rcaron
  656.     /sacute
  657.     /scaron
  658.     /scedilla
  659.     /section
  660.     /sterling
  661.     /tcaron
  662.     /tcedilla
  663.     /thorn
  664.     /uacute
  665.     /ucircumflex
  666.     /udieresis
  667.     /ugrave
  668.     /uhungarumlaut
  669.     /uring
  670.     /yacute
  671.     /ydieresis
  672.     /zacute
  673.     /zcaron
  674.     /zdot
  675. counttomark
  676.     { .letter.chars exch dup put }
  677. repeat
  678. pop
  679.  
  680. % Define a set of characters which, if they occur at the start of a line,
  681. % are taken as indicating a paragraph break.
  682. /.break.chars 50 dict def
  683. mark
  684.     /bullet /dagger /daggerdbl /periodcentered /section
  685.     counttomark
  686.         { .break.chars exch dup put }
  687.     repeat
  688. pop
  689.  
  690. % Define character translation to ASCII.
  691. % We have to do this for the entire character set.
  692.  
  693. /.char.map 500 dict def
  694.  
  695. /.chars.def { counttomark 2 idiv { .char.map 3 1 roll put } repeat pop } def
  696.  
  697. % Encode the printable ASCII characters.
  698.  
  699. mark 32 1 126
  700.  { 1 string dup 0 4 -1 roll put
  701.    dup 0 get StandardEncoding exch get exch
  702.  }
  703. for .chars.def
  704.  
  705.         % Encode accents.
  706. mark
  707.     /acute      (')
  708.     /caron      (^)
  709.     /cedilla    (,)
  710.     /circumflex (^)
  711.     /dieresis   (")
  712.     /grave      (`)
  713.     /ring       (*)
  714.     /tilde      (~)
  715. .chars.def
  716.  
  717.         % Encode the ISO accented characters.
  718. mark 192 1 255
  719.  { ISOLatin1Encoding exch get =string cvs
  720.    dup 0 1 getinterval 1 index dup length 1 sub 1 exch getinterval
  721.    .char.map 2 index known .char.map 2 index known and
  722.     { .char.map 3 -1 roll get .char.map 3 -1 roll get concatstrings
  723.       .char.map 3 1 roll put
  724.     }
  725.     { pop pop pop
  726.     }
  727.    ifelse
  728.  }
  729. for .chars.def
  730.  
  731. % Encode the remaining standard and ISO alphabetic characters.
  732.  
  733. mark
  734.   /AE (AE) /Eth (DH) /OE (OE) /Thorn (Th)
  735.   /ae (ae) /eth (dh)
  736.   /ffi (ffi) /ffl (ffl) /fi (fi) /fl (fl)
  737.   /germandbls (ss) /oe (oe) /thorn (th)
  738. .chars.def
  739.  
  740. % Encode the other standard and ISO characters.
  741.  
  742. mark
  743.   /brokenbar (|) /bullet (*) /copyright ((C)) /currency (#)
  744.   /dagger (#) /daggerdbl (##) /degree (o) /divide (/) /dotaccent (.)
  745.   /dotlessi (i)
  746.   /ellipsis (...) /emdash (--) /endash (-) /exclamdown (!)
  747.   /florin (f) /fraction (/)
  748.   /guillemotleft (<<) /guillemotright (>>)
  749.   /guilsinglleft (<) /guilsinglright (>) /hungarumlaut ("") /logicalnot (~)
  750.   /macron (_) /minus (-) /mu (u) /multiply (*)
  751.   /ogonek (,) /onehalf (1/2) /onequarter (1/4) /onesuperior (1)
  752.   /ordfeminine (-a) /ordmasculine (-o)
  753.   /paragraph (||) /periodcentered (*) /perthousand (o/oo) /plusminus (+-)
  754.   /questiondown (?) /quotedblbase (") /quotedblleft (") /quotedblright (")
  755.   /quotesinglbase (,) /quotesingle (') /registered ((R))
  756.   /section ($) /sterling (#)
  757.   /threequarters (3/4) /threesuperior (3) /trademark ((TM)) /twosuperior (2)
  758.   /yen (Y)
  759. .chars.def
  760.  
  761. % Encode a few common Symbol characters.
  762.  
  763. mark
  764.   /asteriskmath (*) /copyrightsans ((C)) /copyrightserif ((C))
  765.   /greaterequal (>=) /lessequal (<=) /registersans ((R)) /registerserif ((R))
  766.   /trademarksans ((TM)) /trademarkserif ((TM))
  767. .chars.def
  768.  
  769. %%* Add a few characters from StandardEncoding and ISOLatin1Encoding
  770. %%* that were missing.
  771.  
  772. mark
  773.     /cent           (c)
  774.     /guilsinglleft  (<)
  775.     /guilsinglright (>)
  776.     /breve          (*)
  777.     /Lslash         (L/)
  778.     /lslash         (l/)
  779. .chars.def
  780.  
  781. %%* Define the OT1Encoding and T1Encoding vectors for use with dvips
  782. %%* files.  Unfortunately, there's no way of telling what font is
  783. %%* really being used within a dvips document, so we can't provide an
  784. %%* appropriate encoding for each individual font.  Instead, we'll
  785. %%* just provide support for the two most popular text encodings, the
  786. %%* OT1 and T1 encodings, and just accept the fact that any font not
  787. %%* using one of those encodings will be rendered as gibberish.
  788. %%* 
  789. %%* OT1 is Knuth's 7-bit encoding for the CMR text fonts, while T1
  790. %%* (aka the Cork encoding) is the 8-bit encoding used by the DC
  791. %%* fonts, a preliminary version of the proposed Extended Computer
  792. %%* Modern fonts.  Unfortunately, T1 is not a strict extension of OT1;
  793. %%* they differ in positions 8#000 through 8#040, 8#074, 8#076, 8#134,
  794. %%* 8#137, 8#173, 8#174, 8#175 and 8#177, so we can't use the same
  795. %%* vector for both.
  796. %%* 
  797. %%* Of course, we also can't reliably tell the difference between an
  798. %%* OT1-encoded font and a T1-encoded font based on the information in
  799. %%* a dvips-created PostScript file.  As a best-guess solution, we'll
  800. %%* use the T1 encoding if the font contains any characters in
  801. %%* positions above 8#177 and the OT1 encoding if it doesn't.
  802.  
  803. /T1Encoding  256 array def
  804.  
  805. /OT1Encoding 256 array def
  806.  
  807. %%* T1Encoding shares a lot with StandardEncoding, so let's start
  808. %%* there.
  809.  
  810. StandardEncoding T1Encoding copy pop
  811.  
  812. /OT1.encode {
  813.     counttomark
  814.     2 idiv
  815.       { OT1Encoding 3 1 roll put }
  816.     repeat
  817.     cleartomark
  818. } def
  819.  
  820. /T1.encode {
  821.     counttomark
  822.     2 idiv
  823.       { T1Encoding 3 1 roll put }
  824.     repeat
  825.     cleartomark
  826. } def
  827.  
  828. mark
  829.     8#000 /grave
  830.     8#001 /acute
  831.     8#002 /circumflex
  832.     8#003 /tilde
  833.     8#004 /dieresis
  834.     8#005 /hungarumlaut
  835.     8#006 /ring
  836.     8#007 /caron
  837.  
  838.     8#010 /breve
  839.     8#011 /macron
  840.     8#012 /dotaccent
  841.     8#013 /cedilla
  842.     8#014 /ogonek
  843.     8#015 /quotesinglbase
  844.     8#016 /guilsinglleft
  845.     8#017 /guilsinglright
  846.  
  847.     8#020 /quotedblleft
  848.     8#021 /quotedblright
  849.     8#022 /quotedblbase
  850.     8#023 /guillemotleft
  851.     8#024 /guillemotright
  852.     8#025 /endash
  853.     8#026 /emdash
  854.     8#027 /cwm
  855.  
  856.     8#030 /perthousandzero
  857.     8#031 /dotlessi
  858.     8#032 /dotlessj
  859.     8#033 /ff
  860.     8#034 /fi
  861.     8#035 /fl
  862.     8#036 /ffi
  863.     8#037 /ffl
  864.  
  865. %%  8#040 through 8#176 follow StandardEncoding
  866.  
  867.     8#177 /hyphen
  868. T1.encode
  869.  
  870. mark
  871.     8#200 /Abreve
  872.     8#201 /Aogonek
  873.     8#202 /Cacute
  874.     8#203 /Ccaron
  875.     8#204 /Dcaron
  876.     8#205 /Ecaron
  877.     8#206 /Eogonek
  878.     8#207 /Gbreve
  879.     8#210 /Lacute
  880.     8#211 /Lcaron
  881.     8#212 /Lslash
  882.     8#213 /Nacute
  883.     8#214 /Ncaron
  884.     8#215 /Eng
  885.     8#216 /Ohungarumlaut
  886.     8#217 /Racute
  887.     8#220 /Rcaron
  888.     8#221 /Sacute
  889.     8#222 /Scaron
  890.     8#223 /Scedilla
  891.     8#224 /Tcaron
  892.     8#225 /Tcedilla
  893.     8#226 /Uhungarumlaut
  894.     8#227 /Uring
  895.     8#230 /Ydieresis
  896.     8#231 /Zacute
  897.     8#232 /Zcaron
  898.     8#233 /Zdot
  899.     8#234 /IJ
  900.     8#235 /Idot
  901.     8#236 /dbar
  902.     8#237 /section
  903.     8#240 /abreve
  904.     8#241 /aogonek
  905.     8#242 /cacute
  906.     8#243 /ccaron
  907.     8#244 /dcaron
  908.     8#245 /ecaron
  909.     8#246 /eogonek
  910.     8#247 /gbreve
  911.     8#250 /lacute
  912.     8#251 /lcaron
  913.     8#252 /lslash
  914.     8#253 /nacute
  915.     8#254 /ncaron
  916.     8#255 /eng
  917.     8#256 /ohungarumlaut
  918.     8#257 /racute
  919.     8#260 /rcaron
  920.     8#261 /sacute
  921.     8#262 /scaron
  922.     8#263 /scedilla
  923.     8#264 /tcaron
  924.     8#265 /tcedilla
  925.     8#266 /uhungarumlaut
  926.     8#267 /uring
  927.     8#270 /ydieresis
  928.     8#271 /zacute
  929.     8#272 /zcaron
  930.     8#273 /zdot
  931.     8#274 /ij
  932.     8#275 /exclamdown
  933.     8#276 /questiondown
  934.     8#277 /sterling
  935.  
  936.     8#300 /Agrave
  937.     8#301 /Aacute
  938.     8#302 /Acircumflex
  939.     8#303 /Atilde
  940.     8#304 /Adieresis
  941.     8#305 /Aring
  942.     8#306 /AE
  943.     8#307 /Ccedilla
  944.     8#310 /Egrave
  945.     8#311 /Eacute
  946.     8#312 /Ecircumflex
  947.     8#313 /Edieresis
  948.     8#314 /Igrave
  949.     8#315 /Iacute
  950.     8#316 /Icircumflex
  951.     8#317 /Idieresis
  952.     8#320 /Eth
  953.     8#321 /Ntilde
  954.     8#322 /Ograve
  955.     8#323 /Oacute
  956.     8#324 /Ocircumflex
  957.     8#325 /Otilde
  958.     8#326 /Odieresis
  959.     8#327 /OE
  960.     8#330 /Oslash
  961.     8#331 /Ugrave
  962.     8#332 /Uacute
  963.     8#333 /Ucircumflex
  964.     8#334 /Udieresis
  965.     8#335 /Yacute
  966.     8#336 /Thorn
  967.     8#337 /Germandbls 
  968.  
  969.     8#340 /agrave
  970.     8#341 /aacute
  971.     8#342 /acircumflex
  972.     8#343 /atilde
  973.     8#344 /adieresis
  974.     8#345 /aring
  975.     8#346 /ae
  976.     8#347 /ccedilla
  977.     8#350 /egrave
  978.     8#351 /eacute
  979.     8#352 /ecircumflex
  980.     8#353 /edieresis
  981.     8#354 /igrave
  982.     8#355 /iacute
  983.     8#356 /icircumflex
  984.     8#357 /idieresis
  985.     8#360 /eth
  986.     8#361 /ntilde
  987.     8#362 /ograve
  988.     8#363 /oacute
  989.     8#364 /ocircumflex
  990.     8#365 /otilde
  991.     8#366 /odieresis
  992.     8#367 /oe
  993.     8#370 /oslash
  994.     8#371 /ugrave
  995.     8#372 /uacute
  996.     8#373 /ucircumflex
  997.     8#374 /udieresis
  998.     8#375 /yacute
  999.     8#376 /thorn
  1000.     8#377 /germandbls
  1001.  
  1002. T1.encode
  1003.  
  1004. %%* Now copy OT1Encoding into T1Encoding and make a few changes.
  1005.  
  1006. T1Encoding OT1Encoding copy pop
  1007.  
  1008. mark
  1009.     8#000 /Gamma
  1010.     8#001 /Delta
  1011.     8#002 /Theta
  1012.     8#003 /Lambda
  1013.     8#004 /Xi
  1014.     8#005 /Pi
  1015.     8#006 /Sigma
  1016.     8#007 /Upsilon
  1017.  
  1018.     8#010 /Phi
  1019.     8#011 /Psi
  1020.     8#012 /Omega
  1021.     8#013 /ff
  1022.     8#014 /fi
  1023.     8#015 /fl
  1024.     8#016 /ffi
  1025.     8#017 /ffl
  1026.  
  1027.     8#020 /dotlessi
  1028.     8#021 /dotlessj
  1029.     8#022 /grave
  1030.     8#023 /acute
  1031.     8#024 /caron
  1032.     8#025 /breve
  1033.     8#026 /macron
  1034.     8#027 /ring
  1035.  
  1036.     8#030 /cedilla
  1037.     8#031 /germandbls
  1038.     8#032 /ae
  1039.     8#033 /oe
  1040.     8#034 /oslash
  1041.     8#035 /AE
  1042.     8#036 /OE
  1043.     8#037 /Oslash
  1044.  
  1045.     8#040 /polishslash
  1046.  
  1047.     8#042 /quotedblright
  1048.  
  1049.     8#074 /exclamdown
  1050.     8#076 /questiondown
  1051.  
  1052.     8#134 /quotedblleft
  1053.     8#137 /dotaccent
  1054.  
  1055.     8#173 /endash
  1056.     8#174 /emdash
  1057.     8#175 /hungarumlaut
  1058.     8#177 /dieresis
  1059. OT1.encode
  1060.  
  1061. %%* And add a few characters from the OT1Encoding
  1062.  
  1063. mark
  1064.     /Gamma              (\\Gamma )
  1065.     /Delta              (\\Delta )
  1066.     /Theta              (\\Theta )
  1067.     /Lambda             (\\Lambda )
  1068.     /Xi                 (\\Xi )
  1069.     /Pi                 (\\Pi )
  1070.     /Sigma              (\\Sigma )
  1071.     /Upsilon            (\\Upsilon )
  1072.  
  1073.     /Phi                (\\Phi )
  1074.     /Psi                (\\Psi )
  1075.     /Omega              (\\Omega )
  1076.  
  1077.     /dotlessj           (j)
  1078.     /ff                 (ff)
  1079.  
  1080.     /cwm                ()
  1081.  
  1082.     /perthousandzero    (0)
  1083.  
  1084.     /polishslash        ()
  1085.  
  1086.     /Abreve             (A*)
  1087.     /Aogonek            (A,)
  1088.     /Cacute             (C')
  1089.     /Ccaron             (C^)
  1090.     /Dcaron             (D^)
  1091.     /Ecaron             (E^)
  1092.     /Eogonek            (E,)
  1093.     /Gbreve             (G*)
  1094.     /Lacute             (L')
  1095.     /Lcaron             (L^)
  1096.     /Nacute             (N')
  1097.     /Ncaron             (N^)
  1098.     /Eng                (NG)
  1099.     /Ohungarumlaut      (O"")
  1100.     /Racute             (R')
  1101.     /Rcaron             (R^)
  1102.     /Sacute             (S')
  1103.     /Scaron             (S^)
  1104.     /Scedilla           (S,)
  1105.     /Tcaron             (T^)
  1106.     /Tcedilla           (T,)
  1107.     /Uhungarumlaut      (U"")
  1108.     /Uring              (U*)
  1109.     /Ydieresis          (Y")
  1110.     /Zacute             (Z')
  1111.     /Zcaron             (Z^)
  1112.     /Zdot               (Z.)
  1113.     /IJ                 (IJ)
  1114.     /Idot               (I.)
  1115.     /dbar               (d-)
  1116.     /abreve             (a*)
  1117.     /aogonek            (a,)
  1118.     /cacute             (c')
  1119.     /ccaron             (c^)
  1120.     /dcaron             (d^)
  1121.     /ecaron             (e^)
  1122.     /eogonek            (e,)
  1123.     /gbreve             (g*)
  1124.     /lacute             (l')
  1125.     /lcaron             (l^)
  1126.     /nacute             (n')
  1127.     /ncaron             (n^)
  1128.     /eng                (ng)
  1129.     /ohungarumlaut      (o"")
  1130.     /racute             (r')
  1131.     /rcaron             (r^)
  1132.     /sacute             (s')
  1133.     /scaron             (s^)
  1134.     /scedilla           (s,)
  1135.     /tcaron             (t^)
  1136.     /tcedilla           (t,)
  1137.     /uhungarumlaut      (u"")
  1138.     /uring              (u*)
  1139.     /zacute             (z')
  1140.     /zcaron             (z^)
  1141.     /zdot               (z.)
  1142.     /ij                 (ij)
  1143.     /Germandbls         (SS)
  1144. .chars.def
  1145.  
  1146. %%* We extend the df-tail command to stick in an Encoding vector (see
  1147. %%* above for a discussion of the T1 and OT1 encodings), put in a
  1148. %%* FontName (which will just be dvips's name for the font, i.e., Fa,
  1149. %%* Fb, etc.) and give each font a separate FontBBox instead of
  1150. %%* letting them all share a single one.
  1151.  
  1152. /dvips.df-tail      % id numcc maxcc df-tail
  1153.   {
  1154.     /nn 9 dict N
  1155.     nn begin
  1156.         %%  
  1157.         %%  Choose an encoding based on the highest position occupied.
  1158.         %%  
  1159.         dup 128 gt { T1Encoding } { OT1Encoding } ifelse
  1160.         /Encoding X
  1161.         /FontType 3 N
  1162.         %%
  1163.         %%  It's ok for all the fonts to share a FontMatrix, but they
  1164.         %%  need to have separate FontBBoxes
  1165.         %%
  1166.     /FontMatrix fntrx N
  1167.     /FontBBox [0 0 0 0] N
  1168.         string /base X
  1169.         array /BitMaps X
  1170.         %%
  1171.         %%  And let's throw in a FontName for good measure
  1172.         %%
  1173.         dup (    ) cvs
  1174.         %%  
  1175.         %%  Make sure each font gets it own private FontName.  -- dmj,
  1176.         %%  12/23/97
  1177.         %%  
  1178.         dup length string copy
  1179.         /FontName X
  1180.         /BuildChar {CharBuilder} N
  1181.     end
  1182.     dup { /foo setfont }
  1183.        2 array copy cvx N
  1184.     load
  1185.        0 nn put
  1186.     /ctr 0 N
  1187.     [
  1188. } def
  1189.  
  1190. %%* This is functionally equivalent to dvips's /D procedure, but it
  1191. %%* also calculates the Font Bounding Box while defining the
  1192. %%* characters.
  1193.  
  1194. /dvips.D   % char-data ch D - : define character bitmap in current font
  1195. {
  1196.     /cc X                           % char-data
  1197.     dup type /stringtype ne {]} if  % char-data
  1198.  
  1199.     /ch-data X
  1200.     nn /base get cc ctr put     % (adds ctr to cc'th position of BASE)
  1201.     nn /BitMaps get
  1202.     ctr
  1203.     ch-data                     % BitMaps ctr char-data
  1204.     sf 1 ne {
  1205.        dup dup length 1 sub dup 2 index S get sf div put
  1206.     } if
  1207.     put                         % puts char-data into BitMaps at index ctr
  1208.     /ctr ctr 1 add N
  1209. %%  
  1210. %%  Make sure the Font Bounding Box encloses the Bounding Box of the
  1211. %%  current character
  1212. %%
  1213.     nn /FontBBox get        % BB
  1214.  
  1215.     dup                     % calculate new llx
  1216.     dup 0 get
  1217.     ch-xoff
  1218.     .min
  1219.     0 exch put
  1220.  
  1221.     dup                     % calculate new lly
  1222.     dup 1 get
  1223.     ch-yoff ch-height sub
  1224.     .min
  1225.     1 exch put
  1226.  
  1227.     dup                     % calculate new urx
  1228.     dup 2 get
  1229.     ch-dx ch-width add
  1230.     .max 
  1231.     2 exch put
  1232.  
  1233.     dup 3 get               % calculate new ury
  1234.     ch-yoff
  1235.     .max 
  1236.     3 exch put
  1237.  
  1238. } def
  1239.  
  1240. %%* Define start-hook to replace df-tail and D by our versions.
  1241. %%* Unfortunately, the user can redefine start-hook and thus bypass
  1242. %%* these changes, but I don't see an obvious way around that.
  1243.  
  1244. userdict /start-hook {
  1245.     TeXDict /df-tail /dvips.df-tail load bind put
  1246.     TeXDict /D       /dvips.D       load bind put
  1247. } put
  1248.  
  1249. %%* Introduce a symbolic constant for hyphens.  (Need to make
  1250. %%* allowance for hyphen being in different place?)
  1251.  
  1252. /.hyphen 45 def
  1253.  
  1254. % Write out a string.  If it ends in a letter and a hyphen,
  1255. % don't write the hyphen, and set .show.last to a hyphen;
  1256. % otherwise, set .show.last to the character (or \000 if it was a hyphen).
  1257. /.show.write    % <string>
  1258.  {
  1259.     dup length 1 ge
  1260.         { dup dup length 1 sub get      % string last_char
  1261.           dup .hyphen eq                % string last_char hyphen?
  1262.             {                           % string last_char
  1263.                 1 index length 1 gt
  1264.                     { 1 index dup length 2 sub get }
  1265.                     { //.show.last 0 get }
  1266.                 ifelse                  % string last_char prev-char
  1267.                 currentfont /Encoding get exch get  % look up prev-char
  1268.                 //.letter.chars exch known          % is it a letter?
  1269.                     { % Remove the hyphen           % string last_char
  1270.                         exch                        % last_char string
  1271.                         dup length 1 sub            % last_char string len-1
  1272.                         0 exch getinterval          % last_char string-1
  1273.                         exch                        % string-1 last_char
  1274.                     }
  1275.                     { pop 0 }                       % string 0
  1276.                 ifelse
  1277.             }
  1278.           if
  1279.           //.show.last 0 3 -1 roll put              % store last_char
  1280.                                                     % in .show.last
  1281.                                                     % If .show.last ==
  1282.                                                     % hyphen, then
  1283.                                                     % last char of
  1284.                                                     % previous string
  1285.                                                     % was a hyphen
  1286.         }
  1287.     if                                          % string
  1288.     { % begin forall                            % c
  1289.         dup                                     % c c
  1290.         currentfont /Encoding get               % c c vec
  1291.         exch get                                % c name
  1292.         dup //.char.map exch known              % c name bool
  1293.           { exch pop }
  1294.           { pop OT1Encoding exch get }
  1295.         ifelse                                  % name
  1296.         //.char.map exch get                    % translation
  1297.         .show.stdout exch writestring
  1298.     }
  1299.     forall
  1300. } odef
  1301.  
  1302. /.showstring1 {                 % string
  1303.     currentpoint .coord         % string x y
  1304.     3 -1 roll dup .showwidth    % x y string dx dy
  1305.     1 index                     % x y string dx dy dx
  1306.     0 rmoveto                   % x y string dx dy
  1307.     .dcoord pop                 % x y string width
  1308.     SIMPLE
  1309.       {                         % x y string width
  1310.         2 index                 % x y string width y
  1311.         //.show.y .iget         % x y string width y old.y
  1312.         %%* 
  1313.         %%* Replaced test "has y changed" by "has y changed by more
  1314.         %%* than the current font height" so that subscripts and
  1315.         %%* superscripts won't cause line/paragraph breaks
  1316.         %%* 
  1317.          sub abs dup            % x y string width dy dy
  1318.          //.show.height .iget
  1319.          gt
  1320.          {                      % x y string width dy
  1321.  
  1322.             %%* Vertical position has changed by more than the font
  1323.             %%* height, so we now try to figure out whether we've
  1324.             %%* started a new paragraph or merely a new line, using a
  1325.             %%* variety of heuristics.
  1326.  
  1327.             %%* If any of the following is true, we start a new
  1328.             %%* paragraph:
  1329.  
  1330.             %%* (a) the current vertical shift is more than 1.1 times
  1331.             %%*     the previous vertical shift, where 1.1 is an
  1332.             %%*     arbitrarily chosen factor that could probably be
  1333.             %%*     refined.
  1334.  
  1335.             dup                 % x y string width dy dy
  1336.             //.show.dy .iget 1.1 mul
  1337.             gt
  1338.             exch
  1339.  
  1340.             %%* Save the new vertical shift
  1341.  
  1342.             //.show.dy exch .iput
  1343.  
  1344.             %%* (b) The vertical shift is more than 1.3 times the
  1345.             %%*     "size" of the current font.  I've removed this
  1346.             %%*     test since it's not really very useful.
  1347.  
  1348. %%*            //.show.dy .iget
  1349. %%*            //.show.height .iget 1.4 mul
  1350. %%*            gt                          % x y string width bool
  1351. %%*            .show.height .iget 0 gt and % only perform test if font
  1352. %%*                                        % height is nonzero
  1353. %%*            or
  1354.  
  1355.             %%* (c) the first character of the new line is one of the
  1356.             %%*     .break.chars
  1357.  
  1358.             2 index length      % x y string width newpar? len
  1359.             0 gt                % x y string width newpar? len>0?
  1360.               {
  1361.                 2 index 0 get   % x y string width newpar? s
  1362.                 currentfont /Encoding get
  1363.                 exch get        % x y string width newpar? s_enc
  1364.                 //.break.chars exch known { pop true } if
  1365.               }
  1366.             if                  % x y string width newpar?
  1367.  
  1368.             %%* (d) The indentation of the new line is greater than
  1369.             %%*     the indentation of the previous line.
  1370.  
  1371.             4 index
  1372.             //.show.indent .iget
  1373.             gt
  1374.             or
  1375.  
  1376.             %%* HOWEVER, if the line ends in a hyphen, we do NOT begin
  1377.             %%* a new paragraph (cf. comment at end of BF2).  --dmj,
  1378.             %%* 12/23/97
  1379.  
  1380.             //.show.last 0 get .hyphen ne
  1381.             and
  1382.  
  1383.             % newpar?
  1384.               { (\n\n) }        % Paragraph
  1385.               {                 % Line
  1386.                                 %%* 
  1387.                                 %%* BF2: If last character on a line is
  1388.                                 %%* a hyphen, we omit the hyphen and
  1389.                                 %%* run the lines together.  Of
  1390.                                 %%* course, this will fail if a word
  1391.                                 %%* with an explicit hyphen (e.g.,
  1392.                                 %%* X-ray) is split across two lines.
  1393.                                 %%* Oh, well.  (What should we do
  1394.                                 %%* about a hyphen that ends a
  1395.                                 %%* "paragraph"?  Perhaps that should
  1396.                                 %%* inhibit a paragraph break.)
  1397.                                 %%*
  1398.                 //.show.last 0 get .hyphen eq
  1399.                     { ()  }
  1400.                     { ( ) }
  1401.                 ifelse          % x y string width char
  1402.               }
  1403.             ifelse
  1404.             //print
  1405.  
  1406.             //.show.y 3 index .iput % x y string width
  1407.             //.show.x 4 index .iput % x y string width
  1408.             //.show.indent 4 index .iput
  1409.          }
  1410.          {                      % x y string width dy
  1411.                   % If the word processor split a hyphenated word within
  1412.                   % the same line, put out the hyphen now.
  1413.             pop
  1414.             //.show.last 0 get .hyphen eq { (-) //print } if
  1415.          }
  1416.         ifelse
  1417.                                 %%* 
  1418.                                 %%* If have moved more than 1 point to
  1419.                                 %%* the right, interpret it as a
  1420.                                 %%* space?  This need to be looked at
  1421.                                 %%* more closely.
  1422.                                 %%* 
  1423.         3 index                     % x y string width x
  1424.         //.show.x .iget 10 add gt   % x y string width bool
  1425.             { ( ) //print }
  1426.         if
  1427.                                     % x y string width
  1428.         4 1 roll                    % width x y string
  1429.         .show.write pop             % width x
  1430.         add //.show.x exch .iput    % <empty>
  1431.       }
  1432.       { (S ) //print .show==4 
  1433.       }
  1434.     ifelse
  1435. } odef
  1436.  
  1437. /.showstring
  1438.  { dup () eq { pop } { .showstring1 } ifelse
  1439.  } bind def
  1440.  
  1441. % Redefine all the string display operators.
  1442.  
  1443. /show {
  1444.     .showfont
  1445.     .showcolor
  1446.     .showstring
  1447. } codef
  1448.  
  1449. % We define all the other operators in terms of .show1.
  1450.  
  1451. /.show1.string ( ) def
  1452. /.show1 { //.show1.string exch 0 exch put //.show1.string .showstring } odef
  1453. /ashow
  1454.  { .showfont .showcolor
  1455.    { .show1 2 copy rmoveto } forall
  1456.    pop pop
  1457.  } codef
  1458. /awidthshow
  1459.  { .showfont .showcolor
  1460.     { dup .show1 4 index eq { 4 index 4 index rmoveto } if
  1461.       2 copy rmoveto
  1462.     }
  1463.    forall
  1464.    pop pop pop pop pop
  1465.  } codef
  1466. /widthshow
  1467.  { .showfont .showcolor
  1468.    //.show1.string 0 4 -1 roll put
  1469.     { //.show1.string search not { exit } if
  1470.       .showstring .showstring
  1471.       2 index 2 index rmoveto
  1472.     } loop
  1473.    .showstring pop pop
  1474.  } codef
  1475. /kshow
  1476.  { .showfont .showcolor
  1477.     %**************** Should construct a closure, in case the procedure
  1478.     %**************** affects the o-stack.
  1479.     { .show1 dup exec } forall pop
  1480.  } codef
  1481.  
  1482. % We don't really do the right thing with the Level 2 show operators,
  1483. % but we do something semi-reasonable.
  1484. /xshow { pop show } codef
  1485. /yshow { pop show } codef
  1486. /xyshow { pop show } codef
  1487. /glyphshow
  1488.  { currentfont /Encoding .knownget not { {} } if
  1489.    0 1 2 index length 1 sub
  1490.     {        % Stack: glyph encoding index
  1491.       2 copy get 3 index eq { exch pop exch pop null exit } if
  1492.       pop
  1493.     }
  1494.    for null eq { (X) dup 0 4 -1 roll put show } { pop } ifelse
  1495.  } codef
  1496.  
  1497. end
  1498.  
  1499. % Bind the operators we just defined, and all the others if we didn't
  1500. % do it before.  Also reenable 'bind' for future files.
  1501.  
  1502. .bindoperators
  1503. NOBIND currentdict systemdict ne and
  1504.  { systemdict begin .bindoperators end }
  1505. if
  1506. NOBIND
  1507.  { /bind /.bind load def }
  1508. if
  1509.  
  1510. % Make systemdict read-only if it wasn't already.
  1511.  
  1512. systemdict wcheck { systemdict readonly pop } if
  1513.  
  1514. % Restore the current local/global VM mode.
  1515.  
  1516. exec
  1517.  
  1518.  
  1519.